#pragma once

#include "utils/simd_math.h"
#include <vector>
#include <cmath>

namespace utils {
namespace simd {

/**
 * @brief 使用SIMD指令计算简单移动平均（SMA）
 * @param data 数据指针
 * @param size 数据大小
 * @param period 周期
 * @param result 结果数组，大小应为 size - period + 1
 */
inline void simpleMovingAverage(const double* data, size_t size, size_t period, double* result) {
    if (size < period || period == 0) return;
    
    size_t result_size = size - period + 1;
    
    // 计算第一个窗口的和
    double window_sum = 0.0;
    for (size_t i = 0; i < period; ++i) {
        window_sum += data[i];
    }
    
    // 第一个结果
    result[0] = window_sum / period;
    
    // 滑动窗口计算其余结果
    for (size_t i = 1; i < result_size; ++i) {
        window_sum = window_sum - data[i - 1] + data[i + period - 1];
        result[i] = window_sum / period;
    }
}

/**
 * @brief 使用SIMD指令计算指数移动平均（EMA）
 * @param data 数据指针
 * @param size 数据大小
 * @param alpha 平滑因子 (0 < alpha <= 1)
 * @param result 结果数组，大小应为size
 */
inline void exponentialMovingAverage(const double* data, size_t size, double alpha, double* result) {
    if (size == 0) return;
    if (alpha <= 0.0 || alpha > 1.0) alpha = 0.1; // 默认值
    
    // 第一个值直接使用
    result[0] = data[0];
    
    // 计算其余值
    for (size_t i = 1; i < size; ++i) {
        result[i] = alpha * data[i] + (1.0 - alpha) * result[i - 1];
    }
}

/**
 * @brief 使用SIMD指令计算加权移动平均（WMA）
 * @param data 数据指针
 * @param size 数据大小
 * @param period 周期
 * @param result 结果数组，大小应为 size - period + 1
 */
inline void weightedMovingAverage(const double* data, size_t size, size_t period, double* result) {
    if (size < period || period == 0) return;
    
    size_t result_size = size - period + 1;
    double weight_sum = period * (period + 1) / 2.0;
    
    for (size_t i = 0; i < result_size; ++i) {
        double sum = 0.0;
        for (size_t j = 0; j < period; ++j) {
            sum += data[i + j] * (period - j);
        }
        result[i] = sum / weight_sum;
    }
}

/**
 * @brief 使用SIMD指令计算布林带
 * @param data 数据指针
 * @param size 数据大小
 * @param period 周期
 * @param deviation 标准差倍数
 * @param middle 中轨结果数组，大小应为 size - period + 1
 * @param upper 上轨结果数组，大小应为 size - period + 1
 * @param lower 下轨结果数组，大小应为 size - period + 1
 */
inline void bollingerBands(const double* data, size_t size, size_t period, double deviation,
                          double* middle, double* upper, double* lower) {
    if (size < period || period == 0) return;
    
    size_t result_size = size - period + 1;
    
    // 计算SMA作为中轨
    simpleMovingAverage(data, size, period, middle);
    
    // 计算标准差并生成上下轨
    for (size_t i = 0; i < result_size; ++i) {
        double sum_sq = 0.0;
        for (size_t j = 0; j < period; ++j) {
            double diff = data[i + j] - middle[i];
            sum_sq += diff * diff;
        }
        double std_dev = std::sqrt(sum_sq / period);
        
        upper[i] = middle[i] + deviation * std_dev;
        lower[i] = middle[i] - deviation * std_dev;
    }
}

/**
 * @brief 使用SIMD指令计算相对强弱指标（RSI）
 * @param data 数据指针
 * @param size 数据大小
 * @param period 周期
 * @param result 结果数组，大小应为 size - 1
 */
inline void relativeStrengthIndex(const double* data, size_t size, size_t period, double* result) {
    if (size <= period + 1) return;
    
    std::vector<double> gains(size - 1);
    std::vector<double> losses(size - 1);
    
    // 计算价格变化
    for (size_t i = 0; i < size - 1; ++i) {
        double change = data[i + 1] - data[i];
        gains[i] = (change > 0) ? change : 0;
        losses[i] = (change < 0) ? -change : 0;
    }
    
    // 计算第一个平均增益和平均损失
    double avg_gain = 0.0;
    double avg_loss = 0.0;
    
    for (size_t i = 0; i < period; ++i) {
        avg_gain += gains[i];
        avg_loss += losses[i];
    }
    
    avg_gain /= period;
    avg_loss /= period;
    
    // 计算第一个RSI
    double rs = (avg_loss < 1e-10) ? 100.0 : avg_gain / avg_loss;
    result[period - 1] = 100.0 - (100.0 / (1.0 + rs));
    
    // 计算其余RSI值
    for (size_t i = period; i < size - 1; ++i) {
        avg_gain = (avg_gain * (period - 1) + gains[i]) / period;
        avg_loss = (avg_loss * (period - 1) + losses[i]) / period;
        
        rs = (avg_loss < 1e-10) ? 100.0 : avg_gain / avg_loss;
        result[i] = 100.0 - (100.0 / (1.0 + rs));
    }
}

/**
 * @brief 使用SIMD指令计算MACD
 * @param data 数据指针
 * @param size 数据大小
 * @param fast_period 快线周期
 * @param slow_period 慢线周期
 * @param signal_period 信号线周期
 * @param macd MACD线结果数组，大小应为size
 * @param signal 信号线结果数组，大小应为size
 * @param histogram 柱状图结果数组，大小应为size
 */
inline void macd(const double* data, size_t size, size_t fast_period, size_t slow_period, size_t signal_period,
               double* macd_line, double* signal_line, double* histogram) {
    if (size <= slow_period) return;
    
    std::vector<double> fast_ema(size);
    std::vector<double> slow_ema(size);
    
    // 计算快线EMA
    double fast_alpha = 2.0 / (fast_period + 1);
    exponentialMovingAverage(data, size, fast_alpha, fast_ema.data());
    
    // 计算慢线EMA
    double slow_alpha = 2.0 / (slow_period + 1);
    exponentialMovingAverage(data, size, slow_alpha, slow_ema.data());
    
    // 计算MACD线
    for (size_t i = 0; i < size; ++i) {
        macd_line[i] = fast_ema[i] - slow_ema[i];
    }
    
    // 计算信号线
    double signal_alpha = 2.0 / (signal_period + 1);
    exponentialMovingAverage(macd_line, size, signal_alpha, signal_line);
    
    // 计算柱状图
    for (size_t i = 0; i < size; ++i) {
        histogram[i] = macd_line[i] - signal_line[i];
    }
}

/**
 * @brief 使用SIMD指令计算随机指标（Stochastic Oscillator）
 * @param high 最高价数组
 * @param low 最低价数组
 * @param close 收盘价数组
 * @param size 数据大小
 * @param k_period K周期
 * @param d_period D周期
 * @param k_result %K结果数组，大小应为 size - k_period + 1
 * @param d_result %D结果数组，大小应为 size - k_period - d_period + 2
 */
inline void stochasticOscillator(const double* high, const double* low, const double* close,
                               size_t size, size_t k_period, size_t d_period,
                               double* k_result, double* d_result) {
    if (size < k_period) return;
    
    size_t k_size = size - k_period + 1;
    
    // 计算%K
    for (size_t i = 0; i < k_size; ++i) {
        double highest_high = high[i];
        double lowest_low = low[i];
        
        for (size_t j = 1; j < k_period; ++j) {
            highest_high = std::max(highest_high, high[i + j]);
            lowest_low = std::min(lowest_low, low[i + j]);
        }
        
        double range = highest_high - lowest_low;
        if (range < 1e-10) {
            k_result[i] = 50.0; // 默认值
        } else {
            k_result[i] = 100.0 * (close[i + k_period - 1] - lowest_low) / range;
        }
    }
    
    // 计算%D（%K的简单移动平均）
    simpleMovingAverage(k_result, k_size, d_period, d_result);
}

/**
 * @brief 使用SIMD指令计算平均真实范围（ATR）
 * @param high 最高价数组
 * @param low 最低价数组
 * @param close 收盘价数组
 * @param size 数据大小
 * @param period 周期
 * @param result 结果数组，大小应为 size - 1
 */
inline void averageTrueRange(const double* high, const double* low, const double* close,
                           size_t size, size_t period, double* result) {
    if (size <= period) return;
    
    std::vector<double> tr(size - 1);
    
    // 计算真实范围（TR）
    tr[0] = high[0] - low[0]; // 第一个TR就是第一天的范围
    
    for (size_t i = 1; i < size; ++i) {
        double hl = high[i] - low[i];
        double hc = std::abs(high[i] - close[i - 1]);
        double lc = std::abs(low[i] - close[i - 1]);
        tr[i - 1] = std::max(std::max(hl, hc), lc);
    }
    
    // 计算第一个ATR（简单平均）
    double sum = 0.0;
    for (size_t i = 0; i < period; ++i) {
        sum += tr[i];
    }
    result[0] = sum / period;
    
    // 计算其余ATR（使用Wilder平滑法）
    for (size_t i = 1; i < size - period; ++i) {
        result[i] = (result[i - 1] * (period - 1) + tr[i + period - 1]) / period;
    }
}

} // namespace simd
} // namespace utils